/*
REWRITTEN BY XINEF
 */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "azjol_nerub.h"

enum Spells
{
    SPELL_CARRION_BEETLES				= 53520,
    SPELL_SUMMON_CARRION_BEETLES		= 53521,
    SPELL_LEECHING_SWARM				= 53467,
    SPELL_POUND							= 53472,
	SPELL_POUND_DAMAGE					= 53509,
	SPELL_IMPALE_PERIODIC				= 53456,
	SPELL_EMERGE						= 53500,
    SPELL_SUBMERGE						= 53421,
	SPELL_SELF_ROOT						= 42716,

	SPELL_SUMMON_DARTER					= 53599,
	SPELL_SUMMON_ASSASSIN				= 53610,
	SPELL_SUMMON_GUARDIAN				= 53614,
	SPELL_SUMMON_VENOMANCER				= 53615,
};

enum Yells
{
    SAY_AGGRO							= 0,
    SAY_SLAY							= 1,
    SAY_DEATH							= 2,
    SAY_LOCUST							= 3,
    SAY_SUBMERGE						= 4,
    SAY_INTRO							= 5
};

enum Misc
{
    ACHIEV_TIMED_START_EVENT			= 20381,

	EVENT_CHECK_HEALTH_25				= 1,
	EVENT_CHECK_HEALTH_50				= 2,
	EVENT_CHECK_HEALTH_75				= 3,
	EVENT_CARRION_BEETELS				= 4,
	EVENT_LEECHING_SWARM				= 5,
	EVENT_IMPALE						= 6,
	EVENT_POUND							= 7,
	EVENT_CLOSE_DOORS					= 8,
	EVENT_EMERGE						= 9,
	EVENT_SUMMON_VENOMANCER				= 10,
	EVENT_SUMMON_DARTER					= 11,
	EVENT_SUMMON_GUARDIAN				= 12,
	EVENT_SUMMON_ASSASSINS				= 13,
	EVENT_ENABLE_ROTATE					= 14,
	EVENT_KILL_TALK						= 15
};

class boss_anub_arak : public CreatureScript
{
	public:
		boss_anub_arak() : CreatureScript("boss_anub_arak") { }

		struct boss_anub_arakAI : public BossAI
		{
			boss_anub_arakAI(Creature* creature) : BossAI(creature, DATA_ANUBARAK_EVENT)
			{
				me->m_SightDistance = 120.0f;
				intro = false;
			}

			bool intro;

			void EnterEvadeMode()
			{
				me->DisableRotate(false);
				BossAI::EnterEvadeMode();
			}

			void MoveInLineOfSight(Unit* who)
			{
				if (!intro && who->GetTypeId() == TYPEID_PLAYER)
				{
					intro = true;
					Talk(SAY_INTRO);
				}
				BossAI::MoveInLineOfSight(who);
			}

			void JustDied(Unit* killer)
			{
				Talk(SAY_DEATH);
				BossAI::JustDied(killer);
			}

			void KilledUnit(Unit* victim)
			{
				if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
				{
					Talk(SAY_SLAY);
					events.ScheduleEvent(EVENT_KILL_TALK, 6000);
				}
			}

			void JustSummoned(Creature* summon)
			{
				summons.Summon(summon);
				if (!summon->IsTrigger())
					summon->SetInCombatWithZone();
			}

			void Reset()
			{
				BossAI::Reset();
				me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
				instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
			}

			void EnterCombat(Unit* )
			{
				Talk(SAY_AGGRO);
				instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);

				events.ScheduleEvent(EVENT_CARRION_BEETELS, 6500);
				events.ScheduleEvent(EVENT_LEECHING_SWARM, 20000);
				events.ScheduleEvent(EVENT_POUND, 15000);
				events.ScheduleEvent(EVENT_CHECK_HEALTH_75, 1000);
				events.ScheduleEvent(EVENT_CHECK_HEALTH_50, 1000);
				events.ScheduleEvent(EVENT_CHECK_HEALTH_25, 1000);
				events.ScheduleEvent(EVENT_CLOSE_DOORS, 5000);
			}

			void SummonHelpers(float x, float y, float z, uint32 spellId)
			{
				const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
				me->SummonCreature(spellInfo->Effects[EFFECT_0].MiscValue, x, y, z);
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (uint32 eventId = events.ExecuteEvent())
				{
					case EVENT_CLOSE_DOORS:
						_EnterCombat();
						break;
					case EVENT_CARRION_BEETELS:
						me->CastSpell(me, SPELL_CARRION_BEETLES, false);
						events.ScheduleEvent(EVENT_CARRION_BEETELS, 25000);
						break;
					case EVENT_LEECHING_SWARM:
						Talk(SAY_LOCUST);
						me->CastSpell(me, SPELL_LEECHING_SWARM, false);
						events.ScheduleEvent(EVENT_LEECHING_SWARM, 20000);
						break;
					case EVENT_POUND:
						if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 10.0f))
						{					
							me->CastSpell(me, SPELL_SELF_ROOT, true);
							me->DisableRotate(true);
							me->SendMovementFlagUpdate();
							events.ScheduleEvent(EVENT_ENABLE_ROTATE, 3300);
							me->CastSpell(target, SPELL_POUND, false);
						}
						events.ScheduleEvent(EVENT_POUND, 18000);
						break;
					case EVENT_ENABLE_ROTATE:
						me->RemoveAurasDueToSpell(SPELL_SELF_ROOT);
						me->DisableRotate(false);
						break;
					case EVENT_CHECK_HEALTH_25:
					case EVENT_CHECK_HEALTH_50:
					case EVENT_CHECK_HEALTH_75:
						if (me->HealthBelowPct(eventId*25))
						{
							Talk(SAY_SUBMERGE);
							me->CastSpell(me, SPELL_IMPALE_PERIODIC, true);
							me->CastSpell(me, SPELL_SUBMERGE, false);
							me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);

							events.DelayEvents(46000, 0);
							events.ScheduleEvent(EVENT_EMERGE, 45000);
							events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 2000);
							events.ScheduleEvent(EVENT_SUMMON_GUARDIAN, 4000);
							events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 15000);
							events.ScheduleEvent(EVENT_SUMMON_VENOMANCER, 20000);
							events.ScheduleEvent(EVENT_SUMMON_DARTER, 30000);
							events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 35000);
							break;
						}
						events.ScheduleEvent(eventId, 500);
						break;
					case EVENT_EMERGE:
						me->CastSpell(me, SPELL_EMERGE, true);
						me->RemoveAura(SPELL_SUBMERGE);
						me->RemoveAura(SPELL_IMPALE_PERIODIC);
						me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
						break;
					case EVENT_SUMMON_ASSASSINS:
						SummonHelpers(509.32f, 247.42f, 239.48f, SPELL_SUMMON_ASSASSIN);
						SummonHelpers(589.51f, 240.19f, 236.0f, SPELL_SUMMON_ASSASSIN);
						break;
					case EVENT_SUMMON_DARTER:
						SummonHelpers(509.32f, 247.42f, 239.48f, SPELL_SUMMON_DARTER);
						SummonHelpers(589.51f, 240.19f, 236.0f, SPELL_SUMMON_DARTER);
						break;
					case EVENT_SUMMON_GUARDIAN:
						SummonHelpers(550.34f, 316.00f, 234.30f, SPELL_SUMMON_GUARDIAN);
						break;
					case EVENT_SUMMON_VENOMANCER:
						SummonHelpers(550.34f, 316.00f, 234.30f, SPELL_SUMMON_VENOMANCER);
						break;
				}

				if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
					DoMeleeAttackIfReady();
			}
		};

		CreatureAI* GetAI(Creature* creature) const
		{
			return new boss_anub_arakAI(creature);
		}
};

class spell_azjol_nerub_carrion_beetels : public SpellScriptLoader
{
	public:
		spell_azjol_nerub_carrion_beetels() : SpellScriptLoader("spell_azjol_nerub_carrion_beetels") { }

		class spell_azjol_nerub_carrion_beetelsAuraScript : public AuraScript
		{
			PrepareAuraScript(spell_azjol_nerub_carrion_beetelsAuraScript)

			void HandleEffectPeriodic(AuraEffect const* aurEff)
			{
				// Xinef: 2 each second
				GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_CARRION_BEETLES, true);
				GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_CARRION_BEETLES, true);
			}

			void Register()
			{
				OnEffectPeriodic += AuraEffectPeriodicFn(spell_azjol_nerub_carrion_beetelsAuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
			}
		};

		AuraScript *GetAuraScript() const
		{
			return new spell_azjol_nerub_carrion_beetelsAuraScript();
		}
};

class spell_azjol_nerub_pound : public SpellScriptLoader
{
    public:
        spell_azjol_nerub_pound() : SpellScriptLoader("spell_azjol_nerub_pound") { }

        class spell_azjol_nerub_pound_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_azjol_nerub_pound_SpellScript);

            void HandleApplyAura(SpellEffIndex effIndex)
            {
                if (Unit* unitTarget = GetHitUnit())
					GetCaster()->CastSpell(unitTarget, SPELL_POUND_DAMAGE, true);
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_azjol_nerub_pound_SpellScript::HandleApplyAura, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_azjol_nerub_pound_SpellScript();
        }
};

class spell_azjol_nerub_impale_summon : public SpellScriptLoader
{
    public:
        spell_azjol_nerub_impale_summon() : SpellScriptLoader("spell_azjol_nerub_impale_summon") { }

        class spell_azjol_nerub_impale_summon_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_azjol_nerub_impale_summon_SpellScript);

            void SetDest(SpellDestination& dest)
            {
                // Adjust effect summon position
				float floorZ = GetCaster()->GetMap()->GetHeight(GetCaster()->GetPositionX(), GetCaster()->GetPositionY(), GetCaster()->GetPositionZ(), true);
				if (floorZ > INVALID_HEIGHT)
					dest._position.m_positionZ = floorZ;
            }

            void Register()
            {
                OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_azjol_nerub_impale_summon_SpellScript::SetDest, EFFECT_0, TARGET_DEST_CASTER);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_azjol_nerub_impale_summon_SpellScript();
        }
};

void AddSC_boss_anub_arak()
{
    new boss_anub_arak();
	new spell_azjol_nerub_carrion_beetels();
	new spell_azjol_nerub_pound();
	new spell_azjol_nerub_impale_summon();
}
